﻿using ArtMath.CommonType;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;
using ArtMath.Command;
using WeifenLuo.WinFormsUI.Docking;
using ArtMath.Resource;
using ArtMath.Converter;
using ArtMath.Core.Helper;
using ArtMath.Attribute;
using ArtMath.Control;
using System.Linq;
using System.ComponentModel;

namespace ArtMath.Window
{
    public partial class PropertyWindow : DockContent
    {
        //Tuple解释：Item1：旧对象，Item2：旧表达式（针对IStringSettable对象），Item3：顶级对象名称
        Dictionary<object, Tuple<object, string, string>> selectedObjectsInfos = new Dictionary<object, Tuple<object, string, string>>();
        string propDesc;
        [Browsable(false)]
        public SketchPad LinkedPad { get; private set; }
        public PropertyWindow()
        {
            InitializeComponent();
        }
        public PropertyGrid PropertyGrid
        {
            get { return propertyGrid1; }
        }
        public void SketchPad_Activated(SketchPad pad)
        {
            LinkedPad = pad;
            if (LinkedPad == null)
            {
                //propertyGrid1.Enabled = false;
                //Enabled = false;
                propertyGrid1.SelectedObjects = null;
                Text = Resources.Translate("Property");
            }
            else
            {
                propertyGrid1.SelectedObjects = LinkedPad.SelectedObjects.ToArray();
                //propertyGrid1.Enabled = true;
                //Enabled = true;
            }
        }
        private void propertyGrid1_SelectedObjectsChanged(object sender, EventArgs e)
        {
            propertyGrid1.Enabled = propertyGrid1.SelectedObjects != null;
        }

        private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            Program.WinDocuments.LinkedDocument.Modified = true;
            if (LinkedPad == null) return;
            bool reset = propertyGrid1.SelectedObjects.Length > 1;
            List<ModifyProperties.OldValueInfo> ls = new List<ModifyProperties.OldValueInfo>();
            object newValue = null;
            foreach (KeyValuePair<object, Tuple<object, string, string>> item in selectedObjectsInfos)
            {
                PropertyInfo pi = item.Key.GetType().GetProperty(e.ChangedItem.PropertyDescriptor.Name);
                if (newValue == null)
                {
                    if (item.Value.Item2 == null)
                    {
                        newValue = pi.GetValue(item.Key, null);
                    }
                    else
                    {
                        newValue = e.ChangedItem.Value.ToString();
                    }
                }
                ModifyProperties.OldValueInfo ovi = new ModifyProperties.OldValueInfo(item.Value.Item3, item.Key, pi, item.Value.Item2 ?? item.Value.Item1);
                ls.Add(ovi);
                if (reset && item.Value.Item2 != null)
                {
                    pi.SetValue(item.Key, item.Value.Item1, null);//首先把属性值重新设置回（防止出现异常）
                }
            }
            foreach (KeyValuePair<object, Tuple<object, string, string>> item in selectedObjectsInfos)
            {
                IStringSettable iss = item.Value.Item1 as IStringSettable;
                if (iss != null)
                {
                    try
                    {
                        iss.SetFromString(newValue as string);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message, Resources.Translate("Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
            LinkedPad.AddNewCommand(new ModifyProperties(ls, propDesc, newValue), false);
        }

        private void propertyGrid1_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
        {
            if (e.NewSelection.GridItemType != GridItemType.Property) return;
            selectedObjectsInfos.Clear();
            GridItem gi = e.NewSelection;
            List<string> ls = new List<string>();
            while (gi.GridItemType == GridItemType.Property)
            {
                ls.Insert(0, gi.PropertyDescriptor.Name);
                gi = gi.Parent;
            }
            string[] localNames = new string[ls.Count];
            foreach (object item in propertyGrid1.SelectedObjects)
            {
                PropertyInfo[] chain = new PropertyInfo[ls.Count];
                object value = item, directOwner = null;
                for (int i = 0; i < chain.Length; i++)
                {
                    if (i == chain.Length - 1)
                    {
                        directOwner = value;
                    }
                    chain[i] = value.GetType().GetProperty(ls[i]);
                    MultilingualDisplayNameAttribute[] mda = value.GetType().GetAttributes<MultilingualDisplayNameAttribute>(ls[i]);
                    localNames[i] = mda?.Length > 0 ? mda[0].DisplayName : ls[i];
                    value = chain[i].GetValue(value, null);
                }
                IName name = item as IName;
                selectedObjectsInfos.Add(directOwner, new Tuple<object, string, string>(value, value is IStringSettable ? value.ToString() : null, name == null ? item.ToString() : name.Name));
            }
            propDesc = string.Join("->", localNames);
        }

        private void PropertyWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.UserClosing)
            {
                DockState = DockState.Hidden;
                e.Cancel = true;
            }
            Program.WinMain.PropertyMenu.Checked = false;
        }
        public void SketchPad_Layer_RefreshWindowsStatus(LayerControl sender, LayerControl.RefreshWindowsStatusEventArgs e)
        {
            if (!propertyGrid1.IsDisposed)
            {
                propertyGrid1.SelectedObjects = e.SelectedObjects;
            }
            if (sender.SelectedItems.Count == 0)
            {
                Text = Resources.Translate("Property");
            }
            else
            {
                Text = $"{Resources.Translate("Property")} - " + (sender.SelectedItems.Count == 1 ? sender.SelectedItems[0].Name : $"({Resources.JoinLocalizedString("Multiple", "Property")})");
            }
        }
        public void SketchPad_Canvas_MouseUp(object sender, MouseEventArgs e)
        {
            switch (e.Button)
            {
                case MouseButtons.Left:
                    propertyGrid1.Refresh();
                    break;
            }
        }
        public void SketchPad_ViewPropertyMenuClick(SketchPad sender)
        {
            if (sender.SelectedObjects.Count == 0)
            {
                propertyGrid1.SelectedObject = sender;
            }
            else
            {
                propertyGrid1.SelectedObjects = sender.SelectedObjects.ToArray();
            }
        }
        public void SketchPad_RefreshMenuClick(SketchPad sender)
        {
            propertyGrid1.Refresh();
        }
    }
}
